#ifndef __UDSF_USER_BOOT_C_
#define __UDSF_USER_BOOT_C_

#include "sdk_ifs_udk_cfg.h"

#include "../udsf/udsf_memory_access.c"

struct udp_read{
	struct udp_area{
		uint8_t buff[UDP_SIZE+8];
		int flag;
	}area[2];
};

static int  udsf_udp_find(uint8_t is_xip,uint8_t udt_src,struct udp_read *s_udp_read) __attribute__((unused));
static int  udsf_udp_udf_check(uint8_t boot_flag,uint8_t udt_src,UDP_2K_t * udp_2k,uint8_t* temp_sram) __attribute__((unused));
static int  udsf_udp_erase(uint8_t is_xip,uint8_t udt_src,struct udp_read *s_udp_read,int ab_index) __attribute__((unused));
static void udsf_udf16_load(uint8_t is_xip,uint8_t udt_src,UDP_2K_t* p_2k) __attribute__((unused));
static int udsf_udp_crc_check(UDP_2K_t *udp_2k) __attribute__((unused));
static int udsf_udp_erase(uint8_t is_xip,uint8_t udt_src,struct udp_read *s_udp_read,int ab_index){
	
	int ret = -1;
	
	uint32_t addr = USRBOOT_INFO_OFFSET + ab_index*USRBOOT_INFO_SIZE_PRE;

	int len = sizeof(s_udp_read->area[0].buff);
	
	if( is_xip ){
		// isr disable
		NVIC->ICER[0] = (1 << ((uint32_t)(USCI1_IRQn) & 0x1F));
		// xip disable
		QSPI->CTRL = (QSPI_CTRL_IE_Msk                                       |\
		QSPI_CTRL_MSB_SEL_Msk                                  |\
		(QSPI_STANDARD << QSPI_CTRL_FRAME_MODE_Pos)            |\
		(QSPI_CLOCK_DIV << QSPI_CTRL_CLK_DIV_Pos)              |\
		(QSPI_DUMMY_DATA_LEN_QUAD << QSPI_CTRL_DUMMY_LEN_Pos)  |\
		(QSPI_READ_CMD_QUAD << QSPI_CTRL_READ_COMMAND_Pos));
	}

	if( is_xip && (udt_src == UDT_SRC_OUTER) ){
		udsf_spiflash_erase_sector(addr + SYSBIN_SIZE_MAX);	
	}
	
	if( is_xip ){
		// xip enable
		QSPI->CTRL = (QSPI_CTRL_BOOT_SEL_Msk                                |\
						 QSPI_CTRL_MSB_SEL_Msk                                 |\
						(QSPI_QUAD_INPUT << QSPI_CTRL_FRAME_MODE_Pos)          |\
						(QSPI_CLOCK_DIV << QSPI_CTRL_CLK_DIV_Pos)              |\
						(QSPI_DUMMY_DATA_LEN_QUAD << QSPI_CTRL_DUMMY_LEN_Pos)  |\
						(QSPI_READ_CMD_QUAD << QSPI_CTRL_READ_COMMAND_Pos));   
		QSPI->CS = 0x0000;
		QSPI->CS |= (QSPI_CS_XIP_ON_Msk | QSPI_CS_CS_HIGH);
		// isr enable
		NVIC->ISER[0] = (1 << ((uint32_t)(USCI1_IRQn) & 0x1F));
	}
	
	udsf_memory_load2sram(addr,is_xip,udt_src,s_udp_read->area[1-ab_index].buff,len);
	
	UDP_2K_t * udp_2k = (UDP_2K_t*)s_udp_read->area[1-ab_index].buff;
	PATCH_ADDR* udf_addr = &udp_2k->paraFunc.udf01_addr;
	for( int j=0;j<UDF_MAX_NUM;j++ ){
		udf_addr[j].srcAddr += udp_2k->paraFunc.ab_area_offset*ab_index;
	}
	udp_2k->paraFunc.ab_area_flag = ab_index+1;
	udp_2k->paraFunc.crcVal = udsf_get_crc((uint8_t*)&udp_2k->paraFunc,udp_2k->paraFunc.crcLen);
	
	if( 0 != udsf_memcmp(s_udp_read->area[0].buff,s_udp_read->area[1].buff,len) ){
		ret = 0;
	}
	
	return ret;
}

static void udsf_udf16_load(uint8_t is_xip,uint8_t udt_src,UDP_2K_t* p_2k){
	
	// sysboot had open the uart isr.
	
	// isr disable
	NVIC->ICER[0] = (1 << ((uint32_t)(USCI1_IRQn) & 0x1F));
	
	udsf_memory_load2sram(p_2k->paraFunc.udf16_addr.srcAddr,is_xip,udt_src,(uint8_t*)p_2k->paraFunc.udf16_addr.dstAddr,p_2k->paraFunc.udf16_len);
	
	// isr enable
	NVIC->ISER[0] = (1 << ((uint32_t)(USCI1_IRQn) & 0x1F));
}
static int udsf_udp_crc_check(UDP_2K_t *udp_2k)
{
	int crc_ok = 0;
	
	do{
		if( (udp_2k->paraANA.crcLen != 96	) ||
		(udp_2k->paraDataPrep.crcLen != 75 ) ||
		(udp_2k->paraALG.crcLen != 1338	) ||
		(udp_2k->paraFunc.crcLen != 228 ) ){
	
			crc_ok = -1;
			break;
		}
			
		if( udp_2k->paraANA.crcVal != udsf_get_crc((uint8_t*)&udp_2k->paraANA,udp_2k->paraANA.crcLen) ){
			crc_ok = -1;
			break;
		}

		if( udp_2k->paraDataPrep.crcVal != udsf_get_crc((uint8_t*)&udp_2k->paraDataPrep,udp_2k->paraDataPrep.crcLen) ){
			crc_ok = -1;
			break;
		}

		if( udp_2k->paraALG.crcVal != udsf_get_crc((uint8_t*)&udp_2k->paraALG,udp_2k->paraALG.crcLen) ){
			crc_ok = -1;
			break;
		}
					
		if( udp_2k->paraFunc.crcVal != udsf_get_crc((uint8_t*)&udp_2k->paraFunc,udp_2k->paraFunc.crcLen) ){
			crc_ok = -1;
			break;
		}

		if( udp_2k->paraFunc.rsv_crc != udsf_get_crc((uint8_t*)&udp_2k->paraRSV,sizeof(udp_2k->paraRSV)) ){
			crc_ok = -1;
			break;
		}		
	}while(0);
	
	return crc_ok;
}

static int udsf_udp_find(uint8_t is_xip,uint8_t udt_src,struct udp_read *s_udp_read){
	
	int ret = -1;
	int len = sizeof(s_udp_read->area[0].buff);
	
	for( int i=0;i<sizeof(struct udp_read)/sizeof(struct udp_area);i++ ){
		s_udp_read->area[i].flag = -1;
		
		uint32_t addr = USRBOOT_INFO_OFFSET + i*USRBOOT_INFO_SIZE_PRE;
		udsf_memory_load2sram(addr,is_xip,udt_src,s_udp_read->area[i].buff,len);
		
		int crc_ok = 0;
		
		UDP_2K_t * udp_2k = (UDP_2K_t*)s_udp_read->area[i].buff;
		
		uint32_t sn = *((uint32_t*)&s_udp_read->area[i].buff[UDP_SIZE]);
		uint32_t sn_invert = *((uint32_t*)&s_udp_read->area[i].buff[UDP_SIZE+4]);

		if( sn+sn_invert == 0xffFFffFF ){
			crc_ok = udsf_udp_crc_check(udp_2k);
		}else{
			crc_ok = -1;
		}
		
		if( crc_ok >= 0 )
		{
			s_udp_read->area[i].flag = 0;
			ret = 0;
			
			PATCH_ADDR* udf_addr = &udp_2k->paraFunc.udf01_addr;
			for( int j=0;j<UDF_MAX_NUM;j++ ){
				udf_addr[j].srcAddr += udp_2k->paraFunc.ab_area_offset*i;
			}
			udp_2k->paraDataPrep.switch_flag = paramDataPrep->switch_flag;
			udp_2k->paraFunc.ab_area_flag = i+1;
			udp_2k->paraFunc.crcVal = udsf_get_crc((uint8_t*)&udp_2k->paraFunc,udp_2k->paraFunc.crcLen);
		}
	}
	
	return ret;
}


static int udsf_udp_udf_check(uint8_t boot_flag,uint8_t udt_src,UDP_2K_t * udp_2k,uint8_t* temp_sram){

	int ret = 0;
	
	if( (udp_2k->paraANA.crcLen != 96	) ||
			(udp_2k->paraDataPrep.crcLen != 75 ) ||
			(udp_2k->paraALG.crcLen != 1338	) ||
			(udp_2k->paraFunc.crcLen != 228 ) ){
		ret = -1;
		return ret;
	}
	
	for( int i=0;i<UDF_MAX_NUM;i++ ){
		if( (udp_2k->paraFunc.udfEn>>i) & 0x1 ){
			PATCH_ADDR* udf_addr = &udp_2k->paraFunc.udf01_addr;
			uint16_t * udf_len = &udp_2k->paraFunc.udf01_len;
			udsf_memory_load2sram(udf_addr[i].srcAddr,boot_flag,udt_src,temp_sram,udf_len[i]+2);
			uint16_t crc = udsf_get_crc(temp_sram,udf_len[i]);
			if( crc != *((uint16_t*)(temp_sram+udf_len[i])) ){
				ret = -1;
				break;
			}
		}
	}
	
	return ret;
}

#endif
